严格模式
# 严格模式
参考链接:http://www.ruanyifeng.com/blog/2013/01/javascript_strict_mode.html
[TOC]
# 一、定义和优点
严格模式是一种特殊的执行模式,它修复了部分语言上的不足(禁用with),提供了更强的错误检查(重复属性,删除delete不可配置的属性等),并增强了安全性(在eval中使用独立作用域等)。
# 二、模式的使用
- function func(){'use strict';}好处:向上兼容。
- 'use strict'; function func(){}指定整个js内的代码都是在严格模式下。
# 三、与普通模式的区别
# 3.1 变量声明
# 3.1.1 全局变量显式声明。
'use strict';
a = 1; // a is not defined
1
2
2
# 3.2 静态绑定
严格模式对动态绑定做了一些限制。某些情况下,只允许静态绑定,即属性和方法到底归属哪个对象,在编译阶段就确定了。
# 3.2.1 禁止使用with语句
- 定义with语句主要是为了简化多次编写同一个对象的工作。
- 在with语句的代码块内部,每个变量首先被认为是一个局部变量,如果在局部环境中找不到该变量的定义,就会查询with对象中是否具有同名的属性。
- 大量使用with语句会导致性能下降,同时造成调试困难,不适用于大型应用程序使用。
- 因为with语句无法在编译时就确定,属性到底归属哪个对象。
// SyntaxError: Strict mode code may not include a with statement
'use strict';
var obj = {};
obj.a = 1;
with(obj){
var b = a;
}
console.log(b); // 非严格模式下则输出1
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 3.2.2 eval变为独立作用域
参考链接:你不知道的 eval (opens new window)
- 正常模式下,Javascript语言有两种变量作用域(scope):全局作用域和函数作用域。严格模式创设了第三种作用域:eval作用域。
- 正常模式下,eval语句的作用域,取决于它处于全局作用域,还是处于函数作用域。
- 严格模式下,eval语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于eval内部,其它地方不可以拿到eval的值。
"use strict";
var x = 2;
console.info(eval("var x = 5; x")); // 5
console.info(x); // 2
1
2
3
4
2
3
4
# 3.3 增强的安全措施
# 3.3.1 this不指向全局对象,而为undefined。
使用构造函数时,如果忘了加new,this不再指向全局对象,而是报错。
function f(){
"use strict";
this.a = 1;
};
f();// TypeError: Cannot set property 'a' of undefined
1
2
3
4
5
6
2
3
4
5
6
# 3.3.2 禁止在函数内部遍历调用栈。
- callee是arguments的一个属性,这个属性是一个指针,指向这个拥有arguments对象的函数,可以用来消除函数内部调用自己的耦合性。
function fn1(){ console.log(arguments.callee); //fn1(){} } fn1();
1
2
3
4
- arguments.length获得的是实参的个数,arguments.callee.length获得的是形参的个数。
- caller是函数的一个属性。如果一个函数f是在全局作用域内被调用的,则f.caller为null。相反,如果一个函数是在另外一个函数作用域内被调用的,则f.caller指向调用它的那个函数。
function f1(){
"use strict";
f1.caller;
f1.arguments;
}
f1();
// TypeError: 'caller', 'callee', and 'arguments' properties
// may not be accessed on strict mode functions or the arguments objects for calls to them
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 3.4 禁止删除变量
# 3.4.1 只有configurable设置为true的对象属性,才能被删除。
"use strict";
var x;
delete x; // SyntaxError: Delete of an unqualified identifier in strict mode.
var o = Object.create(null, {'x': {
value: 1,
configurable: true
}});
console.log(o.x); // 1
delete o.x;
console.log(o.x); // undefined
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 3.5 显式报错
# 3.5.1 禁止对只读属性赋值。
正常模式下,对一个对象的只读属性进行赋值,不会报错,只会默默地失败。严格模式下,将报错。
'use strict';
var o = Object.create(null, {'x': {
value: 1,
writable: false
}});
o.x = 2;
// TypeError: Cannot assign to read only property 'x' of object '[object Object]'
1
2
3
4
5
6
7
2
3
4
5
6
7
# 3.5.2 禁止对getter方法读取的属性赋值。
"use strict";
var o = {
get v() { return 1; }
};
o.v = 2; // TypeError: Cannot set property v of #<Object> which has only a getter
1
2
3
4
5
2
3
4
5
# 3.5.3 禁止对禁止扩展的对象添加属性。
"use strict";
var o = {};
Object.preventExtensions(o);
o.v = 1; // TypeError: Cannot add property v, object is not extensible
1
2
3
4
2
3
4
# 3.5.4 禁止删除不可删除的属性。
"use strict";
delete Object.prototype; // TypeError: Cannot delete property 'prototype' of function Object() { [native code] }
1
2
2
# 3.6 重名错误
# 3.6.1 对象不能有重名的属性。
正常模式下,如果对象有多个重名属性,最后赋值的那个属性会覆盖前面的值。严格模式下,这属于语法错误。(亲测不实)
"use strict";
var o = {
p: 1,
p: 2
}; // 并没有报错
1
2
3
4
5
2
3
4
5
# 3.6.2 函数不能有重名的参数。
正常模式下,如果函数有多个重名的参数,可以用arguments[i]读取。严格模式下,这属于语法错误。
"use strict";
function fn(a, a){return;}
// SyntaxError: Duplicate parameter name not allowed in this context
1
2
3
2
3
# 3.7 禁止八进制表示法
# 3.7.1 禁止整数第一位为0。
正常模式下,整数的第一位如果是0,表示这是八进制数,比如0100等于十进制的64。严格模式禁止这种表示法,整数第一位为0,将报错。
"use strict";
let a = 0100;
// SyntaxError: Octal literals are not allowed in strict mode.
1
2
3
2
3
# 3.8 arguments对象的限制
# 3.8.1 禁止对arguments赋值。
"use strict";
arguments++; // SyntaxError: Unexpected eval or arguments in strict mode
var obj = { set p(arguments) { } }; // 同上
try { } catch (arguments) { } // 同上
function arguments() { } // 同上
var f = new Function("arguments", "'use strict'; return 17;"); // 同上
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 3.8.2 arguments不再追踪参数的变化。
不管参数传与不传,对arguments无影响,但是对象的属性除外。
!function(a) {
arguments[0] = 100;
console.log(a); // 100
}(1);
// 未传参,失去绑定关系,始终为undefined
!function(a) {
arguments[0] = 100;
console.log(a); // undefined
}();
!function(a) {
'use strict';
arguments[0] = 100;
console.log(a); // 1
}(1);
!function(a) {
'use strict';
arguments[0].x = 100;
console.log(a.x); // 100
}({x:1});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 3.8.3 禁止使用arguments.callee。
"use strict";
var f = function() { return arguments.callee; };
f();
// TypeError: 'caller', 'callee', and 'arguments' properties
// may not be accessed on strict mode functions or the arguments objects for calls to them
1
2
3
4
5
2
3
4
5
# 3.9 函数声明必须在顶层
# 3.9.1 只允许在全局作用域或函数作用域的顶层声明函数。
不允许在非函数的代码块内声明函数。(亲测不实)
"use strict";
if (true) {
function f() { } // 亲测未报错
}
for (var i = 0; i < 5; i++) {
function f2() { } // 亲测未报错
}
1
2
3
4
5
6
7
2
3
4
5
6
7